//
//  TaskWeeklyLetterExt.swift
//  imprint
//
//  Created by 小柠檬🍋 on 2025/3/18.
//

import Foundation
import Foundation
import SwiftUI
//来信任务创建
class TaskWeeklyLetterExt : BaseViewModel {
    static let instance = TaskWeeklyLetterExt()
    private var viewModel = WeeklyLetterViewModel()
    //首次ai任务
    private var mapDelay : [String?:Bool] = [:]
    private let modeType = IAiModelType.weeklyLetter.rawValue
    private let mapQueue = DispatchQueue(label: "mapDelayQueue")
    private let tag = "checkLetter"
    
    func getMapValue(_ key: String) -> Bool {
        return mapQueue.sync {
            self.mapDelay[key] ?? false
        }
    }
    
    func putMapValue(_ key: String,_ bool: Bool) {
        return mapQueue.sync {
            self.mapDelay[key] = bool
        }
    }
    
    func removeMapValue(_ key: String) {
        return mapQueue.sync {
            self.mapDelay.removeValue(forKey: key)
        }
    }
    
    func doCheck() {
        request(isLoading: false,timeout: 60 * 60) {
            showLog(self.tag,"开始检查ai来信")
            try check(self.tag, !isExamine()) {
                "审核版本，不开启功能"
            }
            try check(self.tag, AppStorageManager.shared.toggleAi) {
                "AI 功能已关闭"
            }
            
            try check(self.tag, AiChatExt.isAiEnabled() || AiCustomUtils.shared.isCustomAi(type: self.modeType)) {
                "AI 功能已用尽,请前往活动领取次数"
            }
            let listTaskBean = try await BackupsManager.shared.getDelegateDiary()?.getLatelyTask(roleId: nil, userId: userManager.getUserId(), type: ITaskType.AI_WEEKLY_LETTER.rawValue, pageSize: 15) ?? []//15条，大概就是5个人，平均3天
            try check(self.tag, listTaskBean.isEmpty == false) {
                "每周来信任务为空"
            }
            return listTaskBean
        }  suc: { (listTaskBean : [TaskBean]) in
            for task in listTaskBean {
                self.doTask(task)
            }
        } fail: { _ in
            
        }
    }
    
    func doTask(_ taskBean: TaskBean,
                _ backup: Bool = false) {
        var errorApi = ""
        request(isLoading: false,timeout: 60 * 60) {
            let exit = self.getMapValue(taskBean.objectId ?? "")
            try check(self.tag, exit == false) {
                "正在检查该来信任务"
            }
            var reissueLetter:ReissueLetterBean? = nil
            do {
                reissueLetter = try fromJson(taskBean.extra, ReissueLetterBean.self)
             } catch {}
            self.putMapValue(taskBean.objectId ?? "", true)
            let aiRole = try await BackupsManager.shared.getDelegateConfig()?.getAiRole(roleId: taskBean.roleId)
            let aiNotEmpty  = aiRole?.objectId?.isEmpty == false
            try check(self.tag, aiNotEmpty) {
                "ai角色已删除"
            }
            showLog(self.tag,"\(String(describing: aiRole?.name))来信任务格式\(String(describing: toJson(taskBean)))")
            //先查询一整周的日历
            let list = self.getLastWeekDays(time: getSecond(time: taskBean.time))
            let firstTime = getMillisecond(list.first ?? 0)
            let endTime = getMillisecond(list.last ?? 0)
            showLog(self.tag,"来信内容开始时间：" + TimeUtils.getDate(time: firstTime, format: "yyyy年MM月dd日 HH时mm分"))
            showLog(self.tag,"来信内容结束时间：" + TimeUtils.getDate(time: endTime, format: "yyyy年MM月dd日 HH时mm分"))
            let listDiary = try await BackupsManager.shared.getDelegateDiary()?.queryHomeDiary(userId: userManager.getUserId(), startTime: firstTime, endTime: endTime, keyword: nil, pageNo: 0, pageSize: 1000) ?? []
            // 按日期分组，并取每个日期的第一个元素
            //由于日记数据库查询是降序，但是我们当天显示的第一天，所以要取最第一个数据，也就是当天最后数据
            let grouped = Dictionary(grouping: listDiary) { diary -> String in
                let date = Date(timeIntervalSince1970: TimeInterval(diary.time) / 1000)
                let formatter = DateFormatter()
                formatter.dateFormat = "yyyy-MM-dd"
                formatter.timeZone = TimeZone(identifier: "UTC") // 根据需求调整时区
                return formatter.string(from: date)
            }.mapValues { $0.last } // 取分组后的取最后一个元素
            // 转换为过滤后的列表
            let filteredList = grouped.compactMap { $0.value }
                .filter { $0.diaryType != "default" }
                .sorted(by: { $0.time < $1.time }) // 保持降序
            
            // 拼接字符串
            let stringBuffer = NSMutableString()
            for (index, diary) in filteredList.enumerated() {
                let separator = (index == filteredList.count - 1) ? "。" : ","
                let timeStr = TimeUtils.getDate(time: diary.time, format: "yyyy-MM-dd HH:mm:ss")
                stringBuffer.append("\(index + 1)、\(timeStr)\n\(diary.content ?? "")\(separator)\n")
            }
            
            showLog(self.tag,"上周日记内容：\(stringBuffer)")
            let aiModel: Int  = configManager.getConfig().aiChat.getAiModel(aiMode: IAiModelType.weeklyLetter)
            var replyStr : String = ""
            let finalAiModel = aiModel
            if backup {
                //启动备用方案
                try await retry(maxRetries: 3, retryDelayMillis: 500) {
                    let aiModeBean = configManager.getConfig().getAiChatMode2(key: self.modeType)
                    errorApi = "\(aiModeBean.host ?? ""),\(aiModeBean.model ?? "")"
                    let bean = AIWeeklyLetterBean(model : aiModeBean.model, content: String(stringBuffer), time: getSecond(time: TimeInterval(taskBean.time)), botRoleBean: RoleBean.get(aiRole!), reissueLetter: reissueLetter)
                    showLog(self.tag,"请求来信：\(String(describing: toJson(bean)))")
                    let result = try await AiNetManager.shared.requestAI(host: aiModeBean.host, token: aiModeBean.token, jsonObject: toJson(bean), modeType: AIChatResultBean.self)
                    replyStr = result.getReplyStr()
                }
            } else if AiCustomUtils.shared.isCustomAi(type: self.modeType) {
                //自定义
                try await retry(maxRetries: 3, retryDelayMillis: 500) {
                    let host = AiCustomUtils.shared.getCustomHost(type: self.modeType)
                    let token = AiCustomUtils.shared.getCustomToken(type: self.modeType)
                    let model = AiCustomUtils.shared.getCustomModel(type: self.modeType)
                    errorApi = "\(host),\(model)"
                    let bean = AIWeeklyLetterBean(model : model, content: String(stringBuffer), time: getSecond(time: TimeInterval(taskBean.time)), botRoleBean: RoleBean.get(aiRole!), reissueLetter: reissueLetter)
                    showLog(self.tag,"请求来信：\(String(describing: toJson(bean)))")
                    let result = try await AiNetManager.shared.requestAI(host: host, token: token, jsonObject: toJson(bean), modeType: AIChatResultBean.self)
                    replyStr = result.getReplyStr()
                }
            } else {
                switch finalAiModel {
                case 1,2:
                    //配置模型
                    try await retry(maxRetries: 1, retryDelayMillis: 500) {
                        let aiModeBean = configManager.getConfig().getAiChatMode(key: self.modeType)
                        errorApi = "\(aiModeBean.host ?? ""),\(aiModeBean.model ?? "")"
                        let bean = AIWeeklyLetterBean(model : aiModeBean.model, content: String(stringBuffer), time: getSecond(time: TimeInterval(taskBean.time)), botRoleBean: RoleBean.get(aiRole!), reissueLetter: reissueLetter)
                        showLog(self.tag,"请求来信：\(String(describing: toJson(bean)))")
                        let result = try await AiNetManager.shared.requestAI(host: aiModeBean.host, token: aiModeBean.token, jsonObject: toJson(bean), modeType: AIChatResultBean.self)
                        replyStr = result.getReplyStr()
                    }
                default:
                    //minmax 模型，正常使用这个模型，因为他能控制回复格式
                    try await retry(maxRetries: 3, retryDelayMillis: 500) {
                        let bean = AIWeeklyLetterMinmaxBean(content: String(stringBuffer), time: getSecond(time: TimeInterval(taskBean.time)), botRoleBean: RoleBean.get(aiRole!))
                        showLog(self.tag,"请求来信：\(String(describing: toJson(bean)))")
                        let result = try await AiNetManager.shared.requestAIMinMax(jsonObject: toJson(bean), modeType: AIChatResultMinmaxBean.self)
                        replyStr = result.getReplyStr(true)
                    }
                }
            }
            showLog(self.tag,"请求来信")
            showLog(self.tag,replyStr)
            try check(self.tag, !isAiReplyProhibit(replyStr), "AI含有违禁词")
            //来信记录写入数据库
            var weeklyLetterBean = WeeklyLetterBean()
            weeklyLetterBean.weekOfYear = taskBean.timeKey
            weeklyLetterBean.time = taskBean.time
            weeklyLetterBean.name = aiRole?.name
            weeklyLetterBean.avatar = aiRole?.avatar
            weeklyLetterBean.roleId = aiRole?.objectId
            weeklyLetterBean.content = replyStr
            weeklyLetterBean.userId = userManager.getUserId()
            weeklyLetterBean.title = reissueLetter?.title
            //写入数据库
            try await retry(maxRetries: 10, retryDelayMillis: 500) {
                weeklyLetterBean = try await BackupsManager.shared.getDelegateDiary()?.updateLastWeekLetter(bean: weeklyLetterBean) ?? WeeklyLetterBean()
            }
            //任务结束
            try await retry(maxRetries: 10, retryDelayMillis: 500) {
                taskBean.execute = true
                _ = try await BackupsManager.shared.getDelegateDiary()?.saveTask(bean: taskBean)
            }
            return (aiRole!, weeklyLetterBean)
        }  suc: { (aiRole : AiRoleBean, weeklyLetterBean: WeeklyLetterBean) in
            self.removeMapValue(taskBean.objectId ?? "")
            if commonManager.isWeeklyLetterOpen {
                commonManager.showWeeklyLetter(aiRole)
            } else {
                commonManager.showWeeklyLetterOpen(false, weeklyLetterBean)
            }
            if !AiCustomUtils.shared.isCustomAi(type: self.modeType) {
                AiChatExt.deductAiChatCountCommon()
            }
        } fail: { it in
            self.removeMapValue(taskBean.objectId ?? "")
            if ERROR.NET_ERRPR.rawValue == it.code {
                AiChatExt.reportError(
                    type: self.modeType,
                    typeName: "来信",
                    message: it.realMessage,
                    errorApi: errorApi)
                
                if let error = configManager.getConfig().getAiError(content: it.realMessage) {
                    showToast(error)
                }
            } else {
                //非自定义使用备用方案
                if !backup && !AiCustomUtils.shared.isCustomAi(type: self.modeType) {
                    showLog(self.tag,"来信使用备用方案")
                    self.doTask(taskBean,true)
                }
            }
        }
    }
    
    func doCreate() {
        request(isLoading: false,timeout: 60 * 60){
            try check(self.tag, !isExamine()) {
                "审核版本，不开启功能"
            }
            let curTime = try await getNetTime()
            let reissueLetter = configManager.getConfig().reissueLetter2 ?? configManager.getConfig().reissueLetter
            let reissueLetter2 = userManager.getExtraConfig().reissueLetter
            let listWeekLetter = try await BackupsManager.shared.getDelegateDiary()?.queryWeekLetter(userId: userManager.getUserId(), pageNo: 0, pageSize: 1) ?? []
            if !listWeekLetter.isEmpty {
                //有来信了，创建下周的来信
                //取5个ai
                let listRole = try await BackupsManager.shared.getDelegateConfig()?.getSelectAiRoleList().prefix(5)
                for aiRole in listRole ?? [] {
                    if (reissueLetter != nil && (reissueLetter?.getKey() ?? "")?.isEmpty == false) {
                        if (reissueLetter!.getCount() > 0) {
                            //补发来信
                            try await self.create(
                                reissueLetter?.getKey() ?? "",
                                getSecond(time: reissueLetter?.getTime() ?? 0),
                                aiRole,
                                reissueLetter
                            )
                            reissueLetter?.count =  (reissueLetter?.count ?? 0) - 1
                        } else {
                            showLog(self.tag, "已超出限制人数")
                        }
                    } else if (reissueLetter2 != nil && (reissueLetter2?.getKey() ?? "")?.isEmpty == false) {
                        if (reissueLetter2!.getCount() > 0) {
                            //补发来信
                            try await self.create(
                                reissueLetter2?.getKey() ?? "",
                                getSecond(time: reissueLetter2?.getTime() ?? 0),
                                aiRole,
                                reissueLetter2
                            )
                            reissueLetter2?.count =  (reissueLetter2?.count ?? 0) - 1
                        } else {
                            showLog(self.tag, "已超出限制人数")
                        }
                    }
                    //循环创建5个任务
                    try await self.create(self.getNextWeekKey(curTime), self.getNextWeekTime(curTime), aiRole, nil)
                }
            } else {
                //创建本周的来信，用于用户体验有这个功能
                //随机一个创建任务
                let aiRole = try await BackupsManager.shared.getDelegateConfig()?.getAiRole(roleId: nil)
                try await self.create("首次", curTime + ( 60 * 5), aiRole, nil)
            }
        } suc: { list in
            showLog(self.tag, "重制用户的补发来信")
            self.viewModel.reissueLetterRead()
        } fail: { _ in
            
        }
    }
    
    func create(_ timeKey:String, _ time: TimeInterval, _ aiRole: AiRoleBean?,
                _ reissueLetterBean: ReissueLetterBean?)  async throws {
        if (timeKey.isEmpty || time == 0) {
            return
        }
        do {
            showLog(tag, "开始创建来信任务")
            let taskName = "每周来信"
            let taskBean = TaskBean()
            taskBean.time = getMillisecond(time) //服务器是毫秒
            taskBean.name = taskName
            taskBean.timeKey = timeKey
            taskBean.roleId = aiRole?.objectId ?? nil
            taskBean.userId = userManager.getUserId()
            taskBean.type = ITaskType.AI_WEEKLY_LETTER.rawValue
            
            if let it = reissueLetterBean {
                if !userManager.isLogin() {
                    showLog(tag, "没有登陆")
                    return
                }
                let diffDay = TimeUtils.getDiffDay(time: userManager.user?.createdAt?.date?.timeIntervalSince1970 ?? 0, time2: getNetTimeLocal())
                if (diffDay < it.getCreateLessThan()) {
                    showLog(tag, "注册天数\(diffDay)少于：\(it.getCreateLessThan())")
                    return
                }
                if (it.memory ?? false) {
                    //如果开启关联记忆，那么就一定要开启记忆注入，如果没有开启，则无法创建
                    if (!AppStorageManager.shared.toggleMemoryInject) {
                        showLog(tag, "当前开启记忆关联，需要开启记忆注入")
                        return
                    }
                }
                if (it.versionIos ?? 0 > getAppVersion()) {
                    showLog(tag,"没有达到最低版本号的要求，无法创建任务")
                    return
                }
                if (getNetTimeLocal() > (getSecond(time: it.getTime()) + (60 * 60 * 24 * 10))) {
                    showLog(tag, "时间已经超过10天，无法创建")
                    return
                }
                //添加额外信息
                taskBean.extra = toJson(it)
            }
            
            try check(tag, aiRole != nil){
                "AI 为空"
            }
            try check(tag, AppStorageManager.shared.toggleAi) {
                "AI 功能已关闭"
            }
            try check(tag, AiChatExt.isAiEnabled() || AiCustomUtils.shared.isCustomAi(type: self.modeType)) {
                "AI 功能已用尽,请前往活动领取次数"
            }
            let exist = try await BackupsManager.shared.getDelegateDiary()?.existTask(
                timeKey: timeKey, roleId: aiRole?.objectId, userId: userManager.getUserId(), type: ITaskType.AI_WEEKLY_LETTER.rawValue
            )
            try check(tag, exist == false) {
                "\(timeKey)来信任务已经存在"
            }
            
            let task = try await BackupsManager.shared.getDelegateDiary()?.saveTask(bean: taskBean)
            let msgId = task?.objectId ?? ""
            try check(tag, msgId.isEmpty == false) {
                "来信消息id为空"
            }
            showLog(self.tag,"创建来信任务\(String(describing: msgId))")
            showLog(self.tag,"创建来来信任务\(TimeUtils.getDate(time: time, format: "yyyy-MM-dd HH:mm:ss"))")
            //开始请求推送
            //开始设置定时推送,需要后台开关配置 或者vip
            if (configManager.getConfig().getSwitchConfig().isPushTask() && configManager.getConfig().getSwitchConfig().isPushAiDiary2) {
                showLog(self.tag,"开始创建来信推送任务")
                try await retry(maxRetries: 5, retryDelayMillis: 1000) {
                    try await PushExt.sendSchedule(taskName: taskName, msgId: msgId, title: aiRole?.name ?? "", content: "给你写了一封信", time: getMillisecond(time))
                }
            }
        } catch {
            showLog(self.tag,"创建来信失败：\(error)")
        }
    }
    
    
    
    
    
    
    /**
     * 获取本周的key
     */
    func getWeekKey(_ time: TimeInterval) -> String {
        let date = Date(timeIntervalSince1970: getSecond(time: time))
        
        var calendar = Calendar(identifier: .gregorian)//.gregorian：使用公历。
        calendar.firstWeekday = 2 // 设置周一为一周的第一天
        calendar.minimumDaysInFirstWeek = 4 // 符合ISO 8601标准，确保第一周至少4天
        
        // 获取传入日期所在周的周一
        guard let currentMonday = calendar.date(from: calendar.dateComponents([.yearForWeekOfYear, .weekOfYear], from: date)) else {
            return ""
        }
        
        // 提取下一周周一的年份、周数和月份
        let components = calendar.dateComponents([.year, .weekOfYear, .month], from: currentMonday)
        var year = components.year!
        let weekOfYear = components.weekOfYear!
        let month = components.month!
        
        // 处理跨年情况：12月的周属于下一年的第一周
        if month == 12 && weekOfYear == 1 {
            year += 1
        }
        
        return "\(year)_\(weekOfYear)"
    }
    
    /**
     * 获取下一周周的key
     */
    func getNextWeekKey(_ time: TimeInterval) -> String {
        let date = Date(timeIntervalSince1970: getSecond(time: time))
        
        var calendar = Calendar(identifier: .gregorian)//.gregorian：使用公历。
        calendar.firstWeekday = 2 // 设置周一为一周的第一天
        calendar.minimumDaysInFirstWeek = 4 // 符合ISO 8601标准，确保第一周至少4天
        
        // 获取传入日期所在周的周一
        guard let currentMonday = calendar.date(from: calendar.dateComponents([.yearForWeekOfYear, .weekOfYear], from: date)) else {
            return ""
        }
        
        // 计算下一周的周一
        guard let nextMonday = calendar.date(byAdding: .day, value: 7, to: currentMonday) else {
            return ""
        }
        
        // 提取下一周周一的年份、周数和月份
        let components = calendar.dateComponents([.year, .weekOfYear, .month], from: nextMonday)
        var year = components.year!
        let weekOfYear = components.weekOfYear!
        let month = components.month!
        
        // 处理跨年情况：12月的周属于下一年的第一周
        if month == 12 && weekOfYear == 1 {
            year += 1
        }
        
        return "\(year)_\(weekOfYear)"
    }
    
    //返回秒
    func getNextWeekTime(_ time: TimeInterval) -> TimeInterval {
        let date = Date(timeIntervalSince1970: getSecond(time: time)) // 转换为秒
        
        var calendar = Calendar(identifier: .gregorian)
        calendar.firstWeekday = 2 // 周一作为一周的第一天
        
        // 获取当前周的周一
        guard let currentMonday = calendar.date(from: calendar.dateComponents([.yearForWeekOfYear, .weekOfYear], from: date)) else {
            return 0
        }
        
        // 计算下一周的周一
        guard let nextMonday = calendar.date(byAdding: .day, value: 7, to: currentMonday) else {
            return 0
        }
        
        // 生成随机时间（6-12点，0-59分，0-59秒）
        let hour = Int.random(in: 6...12)
        let minute = Int.random(in: 0..<60)
        let second = Int.random(in: 0..<60)
        
        // 组合日期和时间
        var components = calendar.dateComponents([.year, .month, .day, .hour, .minute, .second, .nanosecond], from: nextMonday)
        components.hour = hour
        components.minute = minute
        components.second = second
        components.nanosecond = 0 // 对应 Kotlin 的 MILLISECOND = 0
        
        guard let finalDate = calendar.date(from: components) else {
            return 0
        }
        
        return finalDate.timeIntervalSince1970
    }
    
    /**
     *  根据时间，获取当前时间的一周时间
     */
    func getWeekDays(time: TimeInterval) -> [TimeInterval] {
        var calendar = Calendar.current
        calendar.firstWeekday = 2 // 设置周一为一周的第一天
        let date = Date(timeIntervalSince1970: time)
        var components = calendar.dateComponents([.yearForWeekOfYear, .weekOfYear], from: date)
        components.weekday = 2 // 设置为周一
        guard let startOfWeek = calendar.date(from: components) else {
            return []
        }
        var result: [TimeInterval] = []
        for i in 0...6 {
            var dayComponents = DateComponents()
            if i != 6 {
                dayComponents.hour = 0
                dayComponents.minute = 0
                dayComponents.second = 0
                dayComponents.nanosecond = 0
            } else {
                dayComponents.hour = 23
                dayComponents.minute = 59
                dayComponents.second = 59
                dayComponents.nanosecond = 999_000_000
            }
            dayComponents.day = i
            if let day = calendar.date(byAdding: dayComponents, to: startOfWeek) {
                result.append(day.timeIntervalSince1970)
            }
        }
        return result
    }
    
    
    
    func getLastWeekDays(time: TimeInterval) -> [TimeInterval] {
        let calendar = Calendar.current
        var date = Date(timeIntervalSince1970: getSecond(time: time))
        
        // 减去一周
        if let lastWeekDate = calendar.date(byAdding: .weekOfYear, value: -1, to: date) {
            date = lastWeekDate
        }
        return getWeekDays(time: date.timeIntervalSince1970)
    }
    
    
}
